package com.youcan.search;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;

import wl.zs.utils.DateUtils;
import wl.zs.utils.TypeValueUtil;

import com.youcan.search.helper.QueryParamBuilder;


/**
 * Solr查询条件。
 * 
 * @author <a href="mailto:zhengs@bsoft.com.cn">zhengshi</a>
 */
public class QueryParams {

	private Pattern pattern = Pattern.compile("\\S+");
	private String fields;
	private List<String> fieldList = new ArrayList<String>();
	private String sort = "";
	private String queryStr;
	private Map<String, Object> queryArgs = new HashMap<String, Object>();
	private int start;
	private int rows;
	private String filterStr;
	private Map<String, String> filterArgs = new HashMap<String, String>();
	private QueryOperation queryOperation;
	private IndexSchema indexSchema;

	public String getFields() {
		if (fields == null && fieldList.size() == 0) {
			return "*";
		}
		StringBuilder sb = new StringBuilder();
		if (fields != null) {
			sb.append(fields);
		}
		for (String field : fieldList) {
			sb.append(",").append(field);
		}
		return sb.charAt(0) == ',' ? sb.substring(1) : sb.toString();
	}

	public void setFields(String fields) {
		this.fields = fields;
		StringTokenizer st = new StringTokenizer(fields, ",");
		while (st.hasMoreTokens()) {
			fieldList.add(st.nextToken());
		}
	}

	public void addField(String field) {
		fieldList.add(field);
	}

	public List<String> getFieldList() {
		return fieldList;
	}

	public void setFieldList(List<String> fieldList) {
		this.fieldList = fieldList;
	}

	public String getSort() {
		return sort;
	}

	public void setSort(String sort) {
		this.sort = sort;
	}

	@SuppressWarnings("unchecked")
	public String getQueryStr() {
		StringBuilder sb = new StringBuilder();
		if (queryStr != null) {
			sb.append(queryStr);
		}
		StringBuilder op = new StringBuilder();
		if (queryOperation == null) {
			op.append(" ");
		} else {
			op.append(" ").append(queryOperation).append(" ");
		}
		for (String name : queryArgs.keySet()) {
			Object value = queryArgs.get(name);
			if (indexSchema.getFieldOrNull(name) == null || value == null) {
				continue;
			}
			if (value instanceof List) {
				StringBuilder s = new StringBuilder();
				for (String str : (List<String>) value) {
					s.append(makeQuery(op, name, str));
				}
				if (s.length() > 0) {
					if (sb.length() > 0) {
						sb.append(op);
					}
					sb.append(s);
				}
			} else {
				if (value == null || value.toString().length() == 0) {
					continue;
				}
				SchemaField sf = indexSchema.getField(name);
				String fieldType = sf.getType().getTypeName();
				StringBuilder s;
				if ("date".equals(fieldType)) {
					s = makeDateQuery(name, value);
				} else {
					s = makeQuery(op, name, TypeValueUtil.getStringValue(value));
				}
				if (s != null && s.length() > 0) {
					if (sb.length() > 0) {
						sb.append(op);
					}
					sb.append(s);
				}
			}
		}
		return sb.toString();
	}

	/**
	 * @param field
	 * @param q
	 * @param weight
	 * @return
	 */
	private StringBuilder makeQuery(StringBuilder op, String field, String q) {
		Matcher m = pattern.matcher(q);
		StringBuilder sb = new StringBuilder();
		while (m.find()) {
			sb.append(op).append(field).append(":").append(m.group());
		}
		return sb.length() > 0 ? sb.delete(0, op.length()) : sb;
	}

	private StringBuilder makeDateQuery(String field, Object q) {
		StringBuilder sb = new StringBuilder();
		if (q instanceof Date) {
			q = DateUtils 
					.toString((Date) q, "yyyy-MM-dd'T'HH'\\':mm'\\':ss'Z'");
		} else {
			q = QueryParamBuilder.formatIndexDate((String) q);
		}
		if (q == null) {
			return sb;
		}
		return sb.append(field).append(":").append(q);
	}

	public void setQueryStr(String queryStr) {
		this.queryStr = queryStr;
	}

	public void addQueryArg(String name, Object value) {
		queryArgs.put(name, value);
	}

	public void removeArg(String name) {
		queryArgs.remove(name);
	}

	public Map<String, Object> getQueryArgs() {
		return queryArgs;
	}

	public void setQueryArgs(Map<String, Object> queryArgs) {
		this.queryArgs = queryArgs;
	}

	public int getStart() {
		return start;
	}

	public void setStart(int start) {
		this.start = start;
	}

	public int getRows() {
		return rows;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}

	public String getFilterStr() {
		if (filterStr == null && filterArgs.size() == 0) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		if (filterStr != null) {
			sb.append(filterStr);
		}
		for (String name : filterArgs.keySet()) {
			if (sb.length() > 0) {
				sb.append(queryOperation == null ? " "
						: (" " + queryOperation + " "));
			}
			sb.append(name).append(":").append(filterArgs.get(name));
		}
		return sb.charAt(0) == ' ' ? sb.substring(1) : sb.toString();
	}

	public Map<String, String> toMap() {
		Map<String, String> map = new HashMap<String, String>();
		map.put("fl", getFields());
		map.put("sort", getSort());
		map.put("q", getQueryStr());
		map.put("start", String.valueOf(getStart()));
		map.put("rows", String.valueOf(getRows()));
		map.put("fq", getFilterStr());
		return map;
	}

	public void addFilterStr(String name, String value) {
		filterArgs.put(name, value);
	}

	public void setFilterStr(String filterStr) {
		this.filterStr = filterStr;
	}

	public Map<String, String> getFilterArgs() {
		return filterArgs;
	}

	public void setFilterArgs(Map<String, String> filterArgs) {
		this.filterArgs = filterArgs;
	}

	public QueryOperation getQueryOperation() {
		return queryOperation;
	}

	public void setQueryOperation(QueryOperation queryOperation) {
		this.queryOperation = queryOperation;
	}

	public IndexSchema getIndexSchema() {
		return indexSchema;
	}

	public void setIndexSchema(IndexSchema indexSchema) {
		this.indexSchema = indexSchema;
	}
}
